#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Windows服务管理器
提供服务安装、卸载、启动、停止等功能
"""

import os
import sys
import time
import ctypes
import subprocess
from typing import Optional, Dict, Any

try:
    import win32serviceutil
    import win32service
    import win32event
    import servicemanager
    import win32api
    import win32con
except ImportError:
    print("错误: 需要安装pywin32库")
    print("请运行: pip install pywin32")
    sys.exit(1)


class ServiceManager:
    """Windows服务管理器"""
    
    def __init__(self, service_name: str, display_name: str, description: str = ""):
        self.service_name = service_name
        self.display_name = display_name
        self.description = description
    
    def is_admin(self) -> bool:
        """检查是否以管理员权限运行"""
        try:
            return ctypes.windll.shell32.IsUserAnAdmin()
        except:
            return False
    
    def run_as_admin(self, command: str) -> bool:
        """以管理员权限运行命令"""
        try:
            if self.is_admin():
                return True
            
            # 请求管理员权限
            result = ctypes.windll.shell32.ShellExecuteW(
                None, "runas", sys.executable, command, None, 1
            )
            return result > 32
        except Exception as e:
            print(f"请求管理员权限失败: {e}")
            return False
    
    def install_service(self, service_path: str, startup_type: str = "manual") -> Dict[str, Any]:
        """安装Windows服务"""
        try:
            if not self.is_admin():
                return {
                    "success": False,
                    "message": "需要管理员权限才能安装服务",
                    "error_code": "ADMIN_REQUIRED"
                }
            
            # 验证服务路径中的文件是否存在
            # service_path格式: 
            # 1. 单个exe文件: "path/to/service.exe"
            # 2. Python脚本: "python.exe" "script.py"
            import shlex
            try:
                # 在Windows环境中，shlex.split会错误处理反斜杠
                # 对于单个exe文件路径，直接使用原始路径
                if service_path.endswith('.exe') and '"' not in service_path:
                    # 单个exe文件，不使用shlex解析
                    args = [service_path.strip()]
                else:
                    # 包含引号或多个参数，使用shlex解析
                    args = shlex.split(service_path)
                
                if len(args) == 1:
                    # 单个exe文件
                    exe_path = args[0]
                    if not os.path.exists(exe_path):
                        return {
                            "success": False,
                            "message": f"服务可执行文件不存在: {exe_path}",
                            "error_code": "EXE_NOT_FOUND"
                        }
                    
                    # 验证是否为exe文件
                    if not exe_path.lower().endswith('.exe'):
                        return {
                            "success": False,
                            "message": f"服务文件必须是exe格式: {exe_path}",
                            "error_code": "INVALID_EXE_FORMAT"
                        }
                        
                elif len(args) >= 2:
                    # Python脚本模式
                    python_exe = args[0]
                    script_path = args[1]
                    
                    if not os.path.exists(python_exe):
                        return {
                            "success": False,
                            "message": f"Python解释器不存在: {python_exe}",
                            "error_code": "PYTHON_NOT_FOUND"
                        }
                    
                    if not os.path.exists(script_path):
                        return {
                            "success": False,
                            "message": f"服务脚本不存在: {script_path}",
                            "error_code": "SCRIPT_NOT_FOUND"
                        }
                else:
                    return {
                        "success": False,
                        "message": f"服务路径格式错误: {service_path}",
                        "error_code": "INVALID_PATH_FORMAT"
                    }
            except Exception as e:
                return {
                    "success": False,
                    "message": f"解析服务路径失败: {service_path}, 错误: {str(e)}",
                    "error_code": "PATH_PARSE_ERROR"
                }
            
            # 设置启动类型
            start_type_map = {
                "auto": win32service.SERVICE_AUTO_START,
                "manual": win32service.SERVICE_DEMAND_START,
                "disabled": win32service.SERVICE_DISABLED
            }
            start_type = start_type_map.get(startup_type, win32service.SERVICE_DEMAND_START)
            
            # 打开服务控制管理器
            scm = win32service.OpenSCManager(None, None, win32service.SC_MANAGER_ALL_ACCESS)
            
            try:
                # 创建服务
                service = win32service.CreateService(
                    scm,
                    self.service_name,
                    self.display_name,
                    win32service.SERVICE_ALL_ACCESS,
                    win32service.SERVICE_WIN32_OWN_PROCESS,
                    start_type,
                    win32service.SERVICE_ERROR_NORMAL,
                    service_path,
                    None,
                    0,
                    None,
                    None,
                    None
                )
                
                # 设置服务描述
                if self.description:
                    win32service.ChangeServiceConfig2(
                        service,
                        win32service.SERVICE_CONFIG_DESCRIPTION,
                        self.description
                    )
                
                win32service.CloseServiceHandle(service)
                
                return {
                    "success": True,
                    "message": f"服务 '{self.display_name}' 安装成功",
                    "service_name": self.service_name
                }
                
            finally:
                win32service.CloseServiceHandle(scm)
                
        except win32service.error as e:
            error_code, error_msg = e.args[:2]
            if error_code == 1073:  # 服务已存在
                return {
                    "success": False,
                    "message": f"服务 '{self.service_name}' 已存在",
                    "error_code": "SERVICE_EXISTS"
                }
            else:
                return {
                    "success": False,
                    "message": f"安装服务失败: {error_msg}",
                    "error_code": f"WIN32_ERROR_{error_code}"
                }
        except Exception as e:
            return {
                "success": False,
                "message": f"安装服务时发生错误: {str(e)}",
                "error_code": "UNKNOWN_ERROR"
            }
    
    def uninstall_service(self) -> Dict[str, Any]:
        """卸载Windows服务"""
        try:
            if not self.is_admin():
                return {
                    "success": False,
                    "message": "需要管理员权限才能卸载服务",
                    "error_code": "ADMIN_REQUIRED"
                }
            
            # 先停止服务
            stop_result = self.stop_service()
            if not stop_result["success"] and stop_result.get("error_code") != "SERVICE_NOT_RUNNING":
                return stop_result
            
            # 打开服务控制管理器
            scm = win32service.OpenSCManager(None, None, win32service.SC_MANAGER_ALL_ACCESS)
            
            try:
                # 打开服务 - 修复DELETE常量问题
                service = win32service.OpenService(scm, self.service_name, win32service.SERVICE_ALL_ACCESS)
                
                try:
                    # 删除服务
                    win32service.DeleteService(service)
                    
                    return {
                        "success": True,
                        "message": f"服务 '{self.display_name}' 卸载成功",
                        "service_name": self.service_name
                    }
                    
                finally:
                    win32service.CloseServiceHandle(service)
                    
            finally:
                win32service.CloseServiceHandle(scm)
                
        except win32service.error as e:
            error_code, error_msg = e.args[:2]
            if error_code == 1060:  # 服务不存在
                return {
                    "success": False,
                    "message": f"服务 '{self.service_name}' 不存在",
                    "error_code": "SERVICE_NOT_EXISTS"
                }
            else:
                return {
                    "success": False,
                    "message": f"卸载服务失败: {error_msg}",
                    "error_code": f"WIN32_ERROR_{error_code}"
                }
        except Exception as e:
            return {
                "success": False,
                "message": f"卸载服务时发生错误: {str(e)}",
                "error_code": "UNKNOWN_ERROR"
            }
    
    def start_service(self) -> Dict[str, Any]:
        """启动Windows服务"""
        try:
            if not self.is_admin():
                return {
                    "success": False,
                    "message": "需要管理员权限才能启动服务",
                    "error_code": "ADMIN_REQUIRED"
                }
            
            # 打开服务控制管理器
            scm = win32service.OpenSCManager(None, None, win32service.SC_MANAGER_ALL_ACCESS)
            
            try:
                # 打开服务
                service = win32service.OpenService(scm, self.service_name, win32service.SERVICE_ALL_ACCESS)
                
                try:
                    # 检查服务状态
                    status = win32service.QueryServiceStatus(service)[1]
                    if status == win32service.SERVICE_RUNNING:
                        return {
                            "success": True,
                            "message": f"服务 '{self.display_name}' 已在运行",
                            "service_name": self.service_name
                        }
                    
                    # 启动服务
                    win32service.StartService(service, None)
                    
                    # 等待服务启动
                    timeout = 30  # 30秒超时
                    start_time = time.time()
                    
                    while time.time() - start_time < timeout:
                        status = win32service.QueryServiceStatus(service)[1]
                        if status == win32service.SERVICE_RUNNING:
                            return {
                                "success": True,
                                "message": f"服务 '{self.display_name}' 启动成功",
                                "service_name": self.service_name
                            }
                        elif status == win32service.SERVICE_STOPPED:
                            return {
                                "success": False,
                                "message": f"服务 '{self.display_name}' 启动失败",
                                "error_code": "SERVICE_START_FAILED"
                            }
                        time.sleep(1)
                    
                    return {
                        "success": False,
                        "message": f"服务 '{self.display_name}' 启动超时",
                        "error_code": "SERVICE_START_TIMEOUT"
                    }
                    
                finally:
                    win32service.CloseServiceHandle(service)
                    
            finally:
                win32service.CloseServiceHandle(scm)
                
        except win32service.error as e:
            error_code, error_msg = e.args[:2]
            if error_code == 1060:  # 服务不存在
                return {
                    "success": False,
                    "message": f"服务 '{self.service_name}' 不存在",
                    "error_code": "SERVICE_NOT_EXISTS"
                }
            else:
                return {
                    "success": False,
                    "message": f"启动服务失败: {error_msg}",
                    "error_code": f"WIN32_ERROR_{error_code}"
                }
        except Exception as e:
            return {
                "success": False,
                "message": f"启动服务时发生错误: {str(e)}",
                "error_code": "UNKNOWN_ERROR"
            }
    
    def stop_service(self) -> Dict[str, Any]:
        """停止Windows服务"""
        try:
            if not self.is_admin():
                return {
                    "success": False,
                    "message": "需要管理员权限才能停止服务",
                    "error_code": "ADMIN_REQUIRED"
                }
            
            # 打开服务控制管理器
            scm = win32service.OpenSCManager(None, None, win32service.SC_MANAGER_ALL_ACCESS)
            
            try:
                # 打开服务
                service = win32service.OpenService(scm, self.service_name, win32service.SERVICE_ALL_ACCESS)
                
                try:
                    # 检查服务状态
                    status = win32service.QueryServiceStatus(service)[1]
                    if status == win32service.SERVICE_STOPPED:
                        return {
                            "success": True,
                            "message": f"服务 '{self.display_name}' 已停止",
                            "service_name": self.service_name,
                            "error_code": "SERVICE_NOT_RUNNING"
                        }
                    
                    # 停止服务
                    win32service.ControlService(service, win32service.SERVICE_CONTROL_STOP)
                    
                    # 等待服务停止
                    timeout = 30  # 30秒超时
                    start_time = time.time()
                    
                    while time.time() - start_time < timeout:
                        status = win32service.QueryServiceStatus(service)[1]
                        if status == win32service.SERVICE_STOPPED:
                            return {
                                "success": True,
                                "message": f"服务 '{self.display_name}' 停止成功",
                                "service_name": self.service_name
                            }
                        time.sleep(1)
                    
                    return {
                        "success": False,
                        "message": f"服务 '{self.display_name}' 停止超时",
                        "error_code": "SERVICE_STOP_TIMEOUT"
                    }
                    
                finally:
                    win32service.CloseServiceHandle(service)
                    
            finally:
                win32service.CloseServiceHandle(scm)
                
        except win32service.error as e:
            error_code, error_msg = e.args[:2]
            if error_code == 1060:  # 服务不存在
                return {
                    "success": False,
                    "message": f"服务 '{self.service_name}' 不存在",
                    "error_code": "SERVICE_NOT_EXISTS"
                }
            else:
                return {
                    "success": False,
                    "message": f"停止服务失败: {error_msg}",
                    "error_code": f"WIN32_ERROR_{error_code}"
                }
        except Exception as e:
            return {
                "success": False,
                "message": f"停止服务时发生错误: {str(e)}",
                "error_code": "UNKNOWN_ERROR"
            }
    
    def get_service_status(self) -> Dict[str, Any]:
        """获取服务状态"""
        try:
            # 打开服务控制管理器
            scm = win32service.OpenSCManager(None, None, win32service.SC_MANAGER_CONNECT)
            
            try:
                # 打开服务
                service = win32service.OpenService(scm, self.service_name, win32service.SERVICE_QUERY_STATUS)
                
                try:
                    # 查询服务状态
                    status_info = win32service.QueryServiceStatus(service)
                    status = status_info[1]
                    
                    status_map = {
                        win32service.SERVICE_STOPPED: "已停止",
                        win32service.SERVICE_START_PENDING: "正在启动",
                        win32service.SERVICE_STOP_PENDING: "正在停止",
                        win32service.SERVICE_RUNNING: "正在运行",
                        win32service.SERVICE_CONTINUE_PENDING: "正在继续",
                        win32service.SERVICE_PAUSE_PENDING: "正在暂停",
                        win32service.SERVICE_PAUSED: "已暂停"
                    }
                    
                    return {
                        "success": True,
                        "service_name": self.service_name,
                        "status": status,
                        "status_text": status_map.get(status, f"未知状态({status})"),
                        "is_running": status == win32service.SERVICE_RUNNING
                    }
                    
                finally:
                    win32service.CloseServiceHandle(service)
                    
            finally:
                win32service.CloseServiceHandle(scm)
                
        except win32service.error as e:
            error_code, error_msg = e.args[:2]
            if error_code == 1060:  # 服务不存在
                return {
                    "success": False,
                    "message": f"服务 '{self.service_name}' 不存在",
                    "error_code": "SERVICE_NOT_EXISTS",
                    "is_running": False
                }
            else:
                return {
                    "success": False,
                    "message": f"查询服务状态失败: {error_msg}",
                    "error_code": f"WIN32_ERROR_{error_code}",
                    "is_running": False
                }
        except Exception as e:
            return {
                "success": False,
                "message": f"查询服务状态时发生错误: {str(e)}",
                "error_code": "UNKNOWN_ERROR",
                "is_running": False
            } 